﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;

namespace BasePlatformNet
{
    public class RDMCore
    {
        #region 常数定义
        // SC Code
        public const byte SC_RDM                               = 0xCC;
        public const byte SC_SUB_MESSAGE                       = 0x01;

        // Command Class
        public const byte DISCOVERY_COMMAND                    = 0x10;
        public const byte GET_COMMAND                          = 0x20;
        public const byte SET_COMMAND                          = 0x30;
        public const byte DISCOVERY_COMMAND_RESPONSE           = 0x11;
        public const byte GET_COMMAND_RESPONSE                 = 0x21;
        public const byte SET_COMMAND_RESPONSE                 = 0x31;

        // ResponseType
        public const byte RESPONSE_TYPE_ACK = 0x00;
        public const byte RESPONSE_TYPE_ACK_TIMER              = 0x01;
        public const byte RESPONSE_TYPE_NACK_REASON            = 0x02;
        public const byte RESPONSE_TYPE_ACK_OVERFLOW           = 0x03;

        // Parameter ID
        //   Category – Network Management
        public const UInt16 DISC_UNIQUE_BRANCH                 = 0x0001;
        public const UInt16 DISC_MUTE                          = 0x0002;
        public const UInt16 DISC_UN_MUTE                       = 0x0003;
        public const UInt16 PROXIED_DEVICES                    = 0x0010;
        public const UInt16 PROXIED_DEVICE_COUNT               = 0x0011;
        public const UInt16 COMMS_STATUS                       = 0x0015;

        //   Category - Status Collection
        public const UInt16 QUEUED_MESSAGE                     = 0x0020;
        public const UInt16 STATUS_MESSAGES                    = 0x0030;
        public const UInt16 STATUS_ID_DESCRIPTION              = 0x0031;
        public const UInt16 CLEAR_STATUS_ID                    = 0x0032;
        public const UInt16 SUB_DEVICE_STATUS_REPORT_THRESHOLD = 0x0033;

        //   Category - RDM Information
        public const UInt16 SUPPORTED_PARAMETERS               = 0x0050;
        public const UInt16 PARAMETER_DESCRIPTION              = 0x0051;

        //   Category – Product Information
        public const UInt16 ICOLOR_INFO = 0x8000;
        public const UInt16 DEVICE_INFO = 0x0060;
        public const UInt16 PRODUCT_DETAIL_ID_LIST = 0x0070;
        public const UInt16 DEVICE_MODEL_DESCRIPTION           = 0x0080;
        public const UInt16 MANUFACTURER_LABEL                 = 0x0081;
        public const UInt16 DEVICE_LABEL                       = 0x0082;
        public const UInt16 FACTORY_DEFAULTS                   = 0x0090;
        public const UInt16 LANGUAGE_CAPABILITIES              = 0x00A0;
        public const UInt16 LANGUAGE                           = 0x00B0;
        public const UInt16 SOFTWARE_VERSION_LABEL             = 0x00C0;
        public const UInt16 BOOT_SOFTWARE_VERSION_ID           = 0x00C1;
        public const UInt16 BOOT_SOFTWARE_VERSION_LABEL        = 0x00C2;

        //   Category - DMX512 Setup
        public const UInt16 DMX_PERSONALITY                    = 0x00E0;
        public const UInt16 DMX_PERSONALITY_DESCRIPTION        = 0x00E1;
        public const UInt16 DMX_START_ADDRESS                  = 0x00F0;
        public const UInt16 SLOT_INFO                          = 0x0120;
        public const UInt16 SLOT_DESCRIPTION                   = 0x0121;
        public const UInt16 DEFAULT_SLOT_VALUE                 = 0x0122;

        //   Category – Sensors 
        public const UInt16 SENSOR_DEFINITION                  = 0x0200;
        public const UInt16 SENSOR_VALUE                       = 0x0201;
        public const UInt16 RECORD_SENSORS                     = 0x0202;

        //   Category – Dimmer Settings


        //   Category – Power/Lamp Settings
        public const UInt16 DEVICE_HOURS                       = 0x0400;
        public const UInt16 LAMP_HOURS                         = 0x0401;
        public const UInt16 LAMP_STRIKES                       = 0x0402;
        public const UInt16 LAMP_STATE                         = 0x0403;
        public const UInt16 LAMP_ON_MODE                       = 0x0404;
        public const UInt16 DEVICE_POWER_CYCLES                = 0x0405;

        //   Category - Display Settings
        public const UInt16 DISPLAY_INVERT                     = 0x0500;
        public const UInt16 DISPLAY_LEVEL                      = 0x0501;

        //   Category – Configuration
        public const UInt16 PAN_INVERT                         = 0x0600;
        public const UInt16 TILT_INVERT                        = 0x0601;
        public const UInt16 PAN_TILT_SWAP                      = 0x0602;
        public const UInt16 REAL_TIME_CLOCK                    = 0x0603;

        //   Category – Control
        public const UInt16 IDENTIFY_DEVICE                    = 0x1000;
        public const UInt16 RESET_DEVICE                       = 0x1001;
        public const UInt16 POWER_STATE                        = 0x1010;
        public const UInt16 PERFORM_SELFTEST                   = 0x1020;
        public const UInt16 SELF_TEST_DESCRIPTION              = 0x1021;
        public const UInt16 CAPTURE_PRESET                     = 0x1030;
        public const UInt16 PRESET_PLAYBACK                    = 0x1031;

        #endregion

        private XmlDocument RDMParameters;

        public string PID2Str(UInt16 pid)
        {
            //if (RDMParaInfoList.ContainsKey(pid))
            //{
            //    return RDMParaInfoList[pid].name;
            //}
            //else
            //{
            //    return pid.ToString("X4");
            //}
            var category = (Catergory)pid;
            return category.ToString();
        }

        public static string Ack2Str(byte ack)
        {
            switch (ack)
            { 
                case RESPONSE_TYPE_ACK:
                    return "ACK";
                case RESPONSE_TYPE_ACK_OVERFLOW:
                    return "OVERFLOW";
                case RESPONSE_TYPE_ACK_TIMER:
                    return "TIMER";
                case RESPONSE_TYPE_NACK_REASON:
                    return "NACK";
                default:
                    return "";
            }
        }

        private string[] UIDtable = { "02f000010203", "02f000010204" };

        private bool overflowFlag;
        private UInt16 oveflowPID;
        private int overflowPoint;
        private Dictionary<UInt16, bool> setAvilableCheckList;
        private Dictionary<UInt16, bool> getAvilableCheckList;
        private List<UInt16> supportedPIDs;
        private int RDMMessageCount;
        private int lastTN;
        private Dictionary<UInt16, RDMParameterInfo> RDMParaInfoList;

        public RDMCore(int num)
        {
            for(int i=0;i<UIDtable.Length;i++)
            {
                StringBuilder sb = new StringBuilder(UIDtable[i]);
                sb[5] = (char)(num + 48);
                UIDtable[i] = sb.ToString();
            }
            lastTN = 0;
            setAvilableCheckList = new Dictionary<ushort, bool>();
            getAvilableCheckList = new Dictionary<ushort, bool>();

            supportedPIDs = new List<ushort>();
            RDMMessageCount = 0;

            //RDMParameters = new XmlDocument();
            //if (File.Exists("./Conf/RDMParameters.xml"))
            //{
            //    RDMParameters.Load("./Conf/RDMParameters.xml");
            //}
            //else
            //{
            //    throw (new Exception("缺少Config文件"));
            //}
            
            //RDMParaInfoList = new Dictionary<ushort,RDMParameterInfo>();
            //GenerateRDMParaList();
        }

        private void GenerateRDMParaList() {
            XmlNodeList paralist = RDMParameters.SelectSingleNode("/pids/base").ChildNodes;
            foreach (XmlNode para in paralist) {
                RDMParameterInfo info = new RDMParameterInfo(para);
                RDMParaInfoList.Add(info.pid, info);
            }
            paralist = RDMParameters.SelectSingleNode("/pids/optional").ChildNodes;
            foreach (XmlNode para in paralist) {
                RDMParameterInfo info = new RDMParameterInfo(para);
                RDMParaInfoList.Add(info.pid, info);
            }
        }

        public List<string> GetUIDList()
        { 
            List<string> uidlist = new List<string>();
            foreach(string s in UIDtable)
            {
                uidlist.Add(s);
            }

            return uidlist;
        }

        public byte[] RDMBuilder(UInt16 pid, byte CommandType, RDMParameters paras)
        {
            RDMGenerator generator = new RDMGenerator(pid, paras.dest_uid);
            generator.CommandClass = CommandType;
            generator.TN = (byte)((lastTN + 1) & 0xff);
            lastTN++;
            generator.PortID = 1;
            generator.SubDev = 0;
            switch (pid)
            { 
                case DEVICE_INFO:
                    generator.ParaLen = 0;
                    generator.Parameter = new byte[1];
                    break;
                case SOFTWARE_VERSION_LABEL:
                    generator.ParaLen = 0;
                    generator.Parameter = new byte[1];
                    break;
                case DMX_START_ADDRESS:
                    if (CommandType == GET_COMMAND)
                    {
                        generator.ParaLen = 0;
                        generator.Parameter = new byte[1];
                    }
                    else
                    {
                        RDMParaDMXAddr dmxp = (RDMParaDMXAddr)paras;
                        generator.ParaLen = 2;
                        generator.Parameter = new byte[2];
                        generator.Parameter[0] = (byte)((dmxp.DMXAddress >> 8) & 0xff);
                        generator.Parameter[1] = (byte)(dmxp.DMXAddress & 0xff);
                    }
                    break;
                case SUPPORTED_PARAMETERS:
                    generator.ParaLen = 0;
                    generator.Parameter = new byte[1];
                    break;
                case PARAMETER_DESCRIPTION:
                    RDMParaDescParas descp = (RDMParaDescParas)paras;
                    generator.ParaLen = 2;
                    generator.Parameter = new byte[2];
                    generator.Parameter[0] = (byte)((descp.pid >> 8) & 0xff);
                    generator.Parameter[1] = (byte)(descp.pid & 0xff);
                    break;
                case IDENTIFY_DEVICE:
                    RDMParaIndetify idfdev = (RDMParaIndetify)paras;
                    generator.ParaLen = 1;
                    generator.Parameter = new byte[1];
                    generator.Parameter[0] = idfdev.IdentifySwitch;
                    break;
                case SENSOR_DEFINITION:
                case SENSOR_VALUE:
                    do
                    {
                        var pd = (RDMParaSensor)paras;
                        generator.ParaLen = 1;
                        generator.Parameter = new byte[] { pd.SensorId }; 
                    } while (false);
                    break;
            }
            return generator.encodeRDM();
        }

        public object RDMResponseHandle(byte[] rdm)
        {
            RDMGenerator generator = new RDMGenerator(rdm);
            if(!((generator.CommandClass == GET_COMMAND_RESPONSE) || (generator.CommandClass == SET_COMMAND_RESPONSE)))
            {
                return null;
            }
            switch (generator.ParameterID) {
                case ICOLOR_INFO:
                    if (generator.Parameter.Length < 10)
                    {
                        return null;
                    }
                    var i_info = new ArtDeviceInfo();
                    i_info.SensorList = new List<ArtSensorInfo>();
                    for (int i = 0; i < 4; i++)
                    {
                        ArtSensorDef ddd = new ArtSensorDef();
                        ArtSensorValue vvv = new ArtSensorValue();
                        ArtSensorInfo sss_info = new ArtSensorInfo();
                        sss_info.Definition = ddd;
                        sss_info.Value = vvv;
                        i_info.SensorList.Add(sss_info);
                    }
                    byte[] i_byte2 = new byte[2];
                    Tools.CopyByte(ref i_byte2, generator.Parameter, 2);
                    i_info.Version = Tools.Byte2HexString(i_byte2).Replace("\n", "");
                    Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 2);
                    i_info.ModelID = Tools.Byte2HexString(i_byte2).Replace("\n", "");
                    Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 4);
                    i_info.Category = Tools.Byte2HexString(i_byte2).Replace("\n", "");
                    if (generator.Parameter.Length >= 40)
                    {
                        byte[] i_byte14 = new byte[14];
                        Tools.CopyByte(ref i_byte14, generator.Parameter, 14, 0, 26);
                        i_info.SoftwareVersionID = System.Text.Encoding.ASCII.GetString(i_byte14);
                    }
                    Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 12);
                    i_info.Personality = Tools.Byte2HexString(i_byte2).Replace("\n", "");

                    if (generator.Parameter.Length >= 26)
                    {
                        //DMX起始地址
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 0);
                        int i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.DMXAddr = i_count;
                        //通道数
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 2);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.LampChannel = i_count;
                        //灯具序号
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 4);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.ChipID = i_count;
                        //传感器个数
                        i_info.SensorCount = 4;
                        //温度配置
                        i_info.SensorList[0].Definition.Type = SensorType.Temperature;
                        i_info.SensorList[0].Definition.Prefix = 1;
                        //温度当前值
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 20);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.SensorList[0].Value.CurrVal = i_count;
                        //温度记录值
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 22);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.SensorList[0].Value.RecordVal = i_count;
                        //电压配置
                        i_info.SensorList[1].Definition.Type = SensorType.Voltage;
                        i_info.SensorList[1].Definition.Prefix = 2;
                        //电压当前值
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 16);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.SensorList[1].Value.CurrVal = i_count;
                        //电压记录值
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 18);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.SensorList[1].Value.RecordVal = i_count;
                        //电流配置
                        i_info.SensorList[2].Definition.Type = SensorType.Current;
                        i_info.SensorList[2].Definition.Prefix = 3;
                        //电流当前值
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 12);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.SensorList[2].Value.CurrVal = i_count;
                        //电流记录值
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 14);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.SensorList[2].Value.RecordVal = i_count;
                        //通道状态配置
                        i_info.SensorList[3].Definition.Type = SensorType.OutError;
                        //通道状态
                        Tools.CopyByte(ref i_byte2, generator.Parameter, 2, 0, 24);
                        i_count = i_byte2[0];
                        i_count = i_count << 8;
                        i_count |= i_byte2[1];
                        i_info.SensorList[3].Value.CurrVal = i_count;
                    }
                    return i_info;
                case DEVICE_INFO:
                    var info = new ArtDeviceInfo();
                    byte[] byte2 = new byte[2];
                    Tools.CopyByte(ref byte2, generator.Parameter, 2);
                    info.Version = Tools.Byte2HexString(byte2).Replace("\n", "");
                    Tools.CopyByte(ref byte2, generator.Parameter, 2, 0, 2);
                    info.ModelID = Tools.Byte2HexString(byte2).Replace("\n", "");
                    Tools.CopyByte(ref byte2, generator.Parameter, 2, 0, 4);
                    info.Category = Tools.Byte2HexString(byte2).Replace("\n", "");
                    byte[] byte4 = new byte[4];
                    Tools.CopyByte(ref byte4, generator.Parameter, 4, 0, 6);
                    info.SoftwareVersionID = Tools.Byte2HexString(byte4).Replace("\n", "");
                    Tools.CopyByte(ref byte2, generator.Parameter, 2, 0, 10);
                    info.Footprint = Tools.Byte2HexString(byte2).Replace("\n", "");
                    Tools.CopyByte(ref byte2, generator.Parameter, 2, 0, 12);
                    info.Personality = Tools.Byte2HexString(byte2).Replace("\n", "");
                    Tools.CopyByte(ref byte2, generator.Parameter, 2, 0, 14);
                    int count = byte2[0];
                    count = count << 8;
                    count |= byte2[1];
                    info.DMXAddr = count;
                    Tools.CopyByte(ref byte2, generator.Parameter, 2, 0, 16);
                    count = byte2[0];
                    count = count << 8;
                    count |= byte2[1];
                    info.SubDeviceCount = count;
                    info.SensorCount = generator.Parameter[18];
                    return info;
                case DEVICE_LABEL:
                case MANUFACTURER_LABEL:
                case SOFTWARE_VERSION_LABEL:
                    StringBuilder label = new StringBuilder();
                    for (int i = 0; i < generator.ParaLen; i++) {
                        char c = (char)generator.Parameter[i];
                        label.Append(c);
                    }
                    return label.ToString();
                case DMX_START_ADDRESS:
                    if (generator.CommandClass != GET_COMMAND_RESPONSE) {
                        break;
                    }
                    int addr = generator.Parameter[0];
                    addr = addr << 8;
                    addr |= generator.Parameter[1];
                    return addr;
                case SUPPORTED_PARAMETERS:
                    //ParaList.Add("ACKType", Ack2Str(generator.ResponseType));
                    //for (int i = 0; i < generator.ParaLen; i+=2)
                    //{
                    //    UInt16 pid = generator.Parameter[i];
                    //    pid = (UInt16)((pid << 8) | generator.Parameter[i+1]);
                    //    ParaList.Add(i.ToString(), pid.ToString());
                    //}
                    break;
                case PARAMETER_DESCRIPTION:
                    //RDMParameterInfo info = new RDMParameterInfo();
                    //UInt16 descpid = generator.Parameter[0];
                    //descpid = (UInt16)((descpid << 8) | generator.Parameter[1]);
                    //info.pid = descpid;


                    //if (generator.ParaLen > 20)
                    //{
                    //    StringBuilder sb = new StringBuilder();
                    //    for (int i = 20; i < 52; i++)
                    //    {
                    //        sb.Append((char)generator.Parameter[i]);
                    //    }

                    //    info.name = sb.ToString();
                    //}
                    //else
                    //{
                        
                    //    info.name = descpid.ToString();
                    //}
                    break;
                case SENSOR_DEFINITION: {
                        var len = generator.ParaLen;
                        if (len < 13) {
                            break;
                        }
                        var pd = generator.Parameter; // for short express
                        var index = pd[0];
                        var type = (SensorType)pd[1];
                        var unit = (SensorUnit)pd[2];
                        var prefix = pd[3];
                        var rangeMin = (pd[4] << 8 | pd[5]);
                        var rangeMax = (pd[6] << 8 | pd[7]);
                        var normalMin = (pd[8] << 8 | pd[9]);
                        var normalMax = (pd[10] << 8 | pd[11]);
                        var recordEn = pd[12] == 0 ? false : true;
                        var description = Encoding.ASCII.GetString(pd, 13, len - 13);
                        var sensorDef = new ArtSensorDef();
                        sensorDef.ID = index;
                        sensorDef.Type = type;
                        sensorDef.Unit = unit;
                        sensorDef.Prefix = prefix;
                        sensorDef.RangeMin = rangeMin;
                        sensorDef.RangeMax = rangeMax;
                        sensorDef.NormalMin = normalMin;
                        sensorDef.NormalMax = normalMax;
                        sensorDef.RecordEn = recordEn;
                        sensorDef.Description = description;
                        return sensorDef;
                    }
                case SENSOR_VALUE: {
                        var len = generator.ParaLen;
                        if (len != 9) {
                            break;
                        }
                        var pd = generator.Parameter; // for short express
                        var index = pd[0];
                        var value = pd[1] << 8 | pd[2];
                        var lowVal = pd[3] << 8 | pd[4];
                        var highVal = pd[5] << 8 | pd[6];
                        var recordVal = pd[7] << 8 | pd[8];
                        var sensorVal = new ArtSensorValue();
                        sensorVal.ID = index;
                        sensorVal.CurrVal = value;
                        sensorVal.LowestVal = lowVal;
                        sensorVal.HighestVal = highVal;
                        sensorVal.RecordVal = recordVal;
                        return sensorVal;
                    }
                default:
                    break;
            }
            return null;
        }

        public byte[] RDMHandle(byte[] rdm)
        {
            RDMGenerator sourceRDM = new RDMGenerator(rdm);
            RDMGenerator generator = new RDMGenerator(sourceRDM);
            generator.MessageCount = RDMMessageCount;
            
            byte command = sourceRDM.CommandClass;
            UInt16 pid = sourceRDM.ParameterID;

            // overflow处理
            if(overflowFlag)
            {
                if(pid != oveflowPID)
                {
                    overflowFlag = false;
                }
            }
            switch (command)
            { 
                case GET_COMMAND:
                    if (getAvilableCheckList.ContainsKey(pid) && getAvilableCheckList[pid])
                    {
                        generator.CommandClass = GET_COMMAND_RESPONSE;
                        switch (pid)
                        { 
                            case SUPPORTED_PARAMETERS:
                                RDMGet_SupportedPara(ref generator);
                                break;
                            default:
                                break;
                        }
                    }
                    else
                    { 
                        Console.WriteLine("[RDMError] Parameter {0} is not avilable for get command",pid);
                        
                    }
                    break;
                case SET_COMMAND:
                    if (setAvilableCheckList.ContainsKey(pid) && setAvilableCheckList[pid])
                    {
                        
                    }
                    else
                    {
                        Console.WriteLine("[RDMError] Parameter {0} is not avilable for set command", pid);
                    }
                    break;
                default:
                    break;
            }
            return generator.encodeRDM();
        }

        #region RDM参数处理
        private void RDMGet_SupportedPara(ref RDMGenerator generator)
        {
            int totallen = supportedPIDs.Count;
            int startpoint = 0;
            if(overflowFlag)
            {
                totallen = totallen - overflowPoint;
                startpoint = overflowPoint;
                overflowFlag = false;
            }

            if (totallen > 115) // 单个RDM包最大容量
            {
                overflowPoint = startpoint + 115;
                overflowFlag = true;
                oveflowPID = SUPPORTED_PARAMETERS;
                generator.ParaLen = 230;
                generator.Parameter = new byte[230];
                generator.ResponseType = RESPONSE_TYPE_ACK_OVERFLOW;

                for (int i = 0; i < 115; i++)
                {
                    UInt16 pid = supportedPIDs[startpoint + i];
                    generator.Parameter[i * 2] = (byte)((pid >> 8) & 0xff);
                    generator.Parameter[i * 2 + 1] = (byte)(pid & 0xff);
                }
            }
            else
            {
                overflowPoint = 0;
                overflowFlag = false;
                generator.ParaLen = totallen*2;
                generator.Parameter = new byte[totallen * 2];
                generator.ResponseType = RESPONSE_TYPE_ACK;

                for (int i = 0; i < totallen; i++)
                {
                    UInt16 pid = supportedPIDs[startpoint + i];
                    generator.Parameter[i * 2] = (byte)((pid >> 8) & 0xff);
                    generator.Parameter[i * 2 + 1] = (byte)(pid & 0xff);
                }
            }

        }
        #endregion

        public class RDMParameterInfo
        {
            public UInt16 pid;
            public string name;
            public bool get_avilable;
            public bool set_avilable;
            public Dictionary<string, string> SetParaDataList;
            public Dictionary<string, string> GetParaDataList;

            public RDMParameterInfo()
            { }
            public RDMParameterInfo(XmlNode node)
            {
                try
                {
                    byte[] idbyte = Tools.String2Bytes(node.Attributes["id"].Value.Substring(2));
                    pid = (UInt16)((idbyte[0] << 8) | (idbyte[1]));
                    name = node.SelectSingleNode("name").InnerText;
                    get_avilable = bool.Parse(node.SelectSingleNode("get").InnerText);
                    set_avilable = bool.Parse(node.SelectSingleNode("set").InnerText);
                    SetParaDataList = new Dictionary<string, string>();
                    GetParaDataList = new Dictionary<string, string>();
                    
                    XmlNode paranode = node.SelectSingleNode("parameters");
                    XmlNodeList paranodelist = null;
                    if ((paranode != null) && (paranode.HasChildNodes))
                    {
                        paranodelist = paranode.ChildNodes;
                    }
                    if (paranodelist != null)
                    {
                        foreach (XmlNode pnode in paranodelist)
                        {
                            if (pnode.Attributes["type"].Equals("get"))
                            {
                                SetParaDataList.Add(pnode.SelectSingleNode("name").InnerText, pnode.SelectSingleNode("init").InnerText);
                            }
                            else if (pnode.Attributes["type"].Equals("set"))
                            {
                                GetParaDataList.Add(pnode.SelectSingleNode("name").InnerText, pnode.SelectSingleNode("init").InnerText);
                            }
                            else if (pnode.Attributes["type"].Equals("all"))
                            {
                                SetParaDataList.Add(pnode.SelectSingleNode("name").InnerText, pnode.SelectSingleNode("init").InnerText);
                                GetParaDataList.Add(pnode.SelectSingleNode("name").InnerText, pnode.SelectSingleNode("init").InnerText);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("[RDMCore]RDMParameterInfo:{0}", e.Message);
                }
            }
        }

        public class RDMGenerator
        {
            public int ParaLen = 0;
            public byte[] Parameter;
            public byte CommandClass; 

            public UInt64 DestUID;
            public UInt64 SourUID;
            public byte TN;
            public byte PortID;
            public byte ResponseType;
            public int MessageCount;
            public UInt16 SubDev;
            public UInt16 ParameterID;

            public UInt16 CheckSum;

            public RDMGenerator(byte[] rdmpacket)
            {
                this.decodeRDM(rdmpacket);
            }
            public RDMGenerator(UInt16 pid, UInt64 dest_uid)
            {
                this.SourUID = 0x02f019371101;
                this.DestUID = dest_uid;
                this.SubDev = 0;
                this.ParameterID = pid;
                this.MessageCount = 0;

            }
            public RDMGenerator(RDMGenerator source)
            {
                //this.CommandClass = (byte)(source.CommandClass + 1);
                this.SourUID = source.DestUID;
                this.DestUID = source.SourUID;
                this.TN = source.TN;
                //this.MessageCount = 0;
                this.SubDev = source.SubDev;
                this.ParameterID = source.ParameterID;
            }

            public byte[] encodeRDM()
            {
                byte[] RDMPacket = new byte[ParaLen + 26];
                RDMPacket[0] = SC_RDM;
                RDMPacket[1] = SC_SUB_MESSAGE;
                RDMPacket[2] = (byte)(ParaLen + 24);
                for (int i = 0; i < 6; i++)
                {
                    RDMPacket[i + 3] = (byte)((DestUID >> (8 * (5 - i))) & 0xff);
                }
                for (int i = 0; i < 6; i++)
                {
                    RDMPacket[i + 9] = (byte)((SourUID >> (8 * (5 - i))) & 0xff);
                }
                RDMPacket[15] = TN;
                if ((CommandClass & 1) != 0)
                {
                    RDMPacket[16] = ResponseType;
                }
                else
                {
                    RDMPacket[16] = PortID;
                }

                if ((MessageCount >= 0) && (MessageCount <= 255))
                {
                    RDMPacket[17] = (byte)MessageCount;
                }
                else if (MessageCount > 255)
                {
                    RDMPacket[17] = 255;
                }
                else
                {
                    RDMPacket[17] = 0;
                }

                RDMPacket[18] = (byte)((SubDev >> 8) & 0xff);
                RDMPacket[19] = (byte)(SubDev & 0xff);

                RDMPacket[20] = CommandClass;

                RDMPacket[21] = (byte)((ParameterID >> 8) & 0xff);
                RDMPacket[22] = (byte)(ParameterID & 0xff);

                RDMPacket[23] = (byte)(ParaLen & 0xff);

                for (int i = 0; i < ParaLen; i++)
                {
                    RDMPacket[24 + i] = Parameter[i];
                }
                CheckSum = 0;
                for (int i = 0; i < ParaLen + 24; i++)
                {
                    CheckSum += RDMPacket[i];
                }

                RDMPacket[24 + ParaLen] = (byte)((CheckSum >> 8) & 0xff);
                RDMPacket[25 + ParaLen] = (byte)(CheckSum & 0xff);

                return RDMPacket;
            }

            public void decodeRDM(byte[] packet)
            {
                this.CommandClass = packet[20];
                this.SourUID = 0;
                this.DestUID = 0;
                for (int i = 0; i < 6; i++)
                {
                    this.SourUID = this.SourUID << 8;
                    this.SourUID |= packet[i + 9];
                    this.DestUID = this.DestUID << 8;
                    this.DestUID |= packet[i + 3];
                }

                this.TN = packet[15];
                if ((CommandClass & 1) == 0)
                {
                    this.PortID = packet[16];
                }
                else
                {
                    this.ResponseType = packet[16];
                }

                this.MessageCount = packet[17];

                this.SubDev = (UInt16)((packet[18] << 8) | packet[19]);
                this.ParameterID = (UInt16)((packet[21] << 8) | packet[22]);
                this.ParaLen = packet[23];
                this.Parameter = new byte[ParaLen];
                Tools.CopyByte(ref this.Parameter, packet, ParaLen, 0, 24);
            }

        }
    }

    
}
